package com.compass.mobile.ui.viewModel

import LogUtil
import android.annotation.SuppressLint
import android.widget.Toast
import androidx.lifecycle.MutableLiveData
import com.compass.mobile.framework.utils.TipsToast
import com.compass.mobile.network.viewmodel.BaseViewModel
import com.compass.mobile.ui.activity.VideoAnswerActivity
import com.netease.nimlib.sdk.NIMClient
import com.netease.nimlib.sdk.RequestCallback
import com.netease.nimlib.sdk.RequestCallbackWrapper
import com.netease.nimlib.sdk.ResponseCode
import com.netease.nimlib.sdk.avsignalling.SignallingService
import com.netease.nimlib.sdk.avsignalling.builder.CallParamBuilder
import com.netease.nimlib.sdk.avsignalling.builder.InviteParamBuilder
import com.netease.nimlib.sdk.avsignalling.constant.ChannelType
import com.netease.nimlib.sdk.avsignalling.event.InvitedEvent
import com.netease.nimlib.sdk.avsignalling.model.ChannelBaseInfo
import com.netease.nimlib.sdk.avsignalling.model.ChannelFullInfo
import toJson
import java.util.UUID


/**
 * Description： 视频通话相关viewModel
 * Date:2024/6/13 11:20
 */
class VideoCallViewModel : BaseViewModel() {
    var tag = "VideoCall:===channel"
    val joinChannelLiveData = MutableLiveData<ChannelFullInfo?>() //本地加入频道
    val remoteUserJoinChannelLiveData = MutableLiveData<ChannelFullInfo?>() //本地加入频道
    /**
     * 创建频道
     * 同一时刻频道名互斥，不能重复创建，但如果频道名缺省，服务器会自动分配频道id。
     * @param type   频道类型 默认为视频
     * @param channelName 频道名，可缺省
     * @param channelExt  频道的自定义扩展信息，可缺省
     * @return InvocationFuture
     */

    fun createRoom(channelName: String?, type: ChannelType? = ChannelType.VIDEO) {

        NIMClient.getService(SignallingService::class.java)
            .create(type, channelName, "").setCallback(
                object : RequestCallbackWrapper<ChannelBaseInfo>() {
                    @SuppressLint("SuspiciousIndentation")
                    override fun onResult(
                        code: Int, channelBaseInfo: ChannelBaseInfo?, throwable: Throwable?
                    ) {
                        if (code == ResponseCode.RES_SUCCESS.toInt()) {

                            LogUtil.d(
                                "创建成功平道成功  channelInfo===${channelBaseInfo?.toJson()}",
                                tag = tag
                            )
                            channelBaseInfo?.let {
                                joinChannel(it)//本地加入频道
                                //随机一个邀请id
                                var invitedRequestId: String =
                                    UUID.randomUUID().toString().trim().replace("-", "").lowercase()
                                    inviteOther(it, "18700836625", invitedRequestId)//要情其他人加入频道
                            }


                        } else {
                            LogUtil.d(
                                "创建失败  ，code==$code exception ==${throwable?.toJson()}",
                                tag = tag
                            )


                        }
                    }
                })
    }

    /**
     * 加入频道
     * @param channelId     对应频道id
     * @param selfUid       自己在频道中对应的uid，可选，大于零有效，无效时服务器会分配随机唯一的uid， 也可以自己生成，但要保证唯一性
     * @param customInfo    操作者附加的自定义信息，透传给其他人，可缺省
     * @param offlineEnable 通知事件是否存离线
     * @param nertcChannelName 云信G2-RTC的房间名，若填了该字段，则会返回 token
     * @param nertcTokenTtl 云信G2-RTC的token的有效期，表示token的过期时间，单位秒，选填，默认10分钟
     * @param nertcJoinRoomQueryParamMap 云信G2-RTC加入房间的请求参数，可以转成json，选填
     * @return InvocationFuture<ChannelFullInfo>
     */
    private fun joinChannel(channelInfo: ChannelBaseInfo) {
        var selfUid = System.nanoTime()
        NIMClient.getService(SignallingService::class.java)
            .join(channelInfo.channelId, selfUid, "", false).setCallback(
                object : RequestCallbackWrapper<ChannelFullInfo?>() {
                    override fun onResult(
                        i: Int, channelFullInfo: ChannelFullInfo?, throwable: Throwable?
                    ) {
                        if (i == ResponseCode.RES_SUCCESS.toInt()) {
                            joinChannelLiveData.value=channelFullInfo
                            LogUtil.d("加入频道成功", tag = tag)
                        } else if (i == ResponseCode.RES_CHANNEL_MEMBER_HAS_EXISTS.toInt()) {
                            LogUtil.d("已经在频道中", tag = tag)
                        } else {

                            LogUtil.d("加入频道失败 code=$i", tag = tag)
                        }
                    }
                })

    }


    /**
     * 离开频道
     * @param channelId     对应频道id
     * @param offlineEnable 通知事件是否存离线
     * @param customInfo    操作者附加的自定义信息，透传给其他人，可缺省
     * @return InvocationFuture<Void>
     */
     fun leave(channelInfo: ChannelBaseInfo) {
        NIMClient.getService(SignallingService::class.java)
            .leave(channelInfo.channelId, false, null).setCallback(
                object : RequestCallbackWrapper<Void?>() {
                    override fun onResult(i: Int, aVoid: Void?, throwable: Throwable?) {
                        if (i == ResponseCode.RES_SUCCESS.toInt()) {
                            LogUtil.d("加入房间成功", tag = tag)
                        } else {
                            LogUtil.d("离开房间失败 code=$i", tag = tag)
                        }
                    }
                })
    }


    /**
     * 关闭频道
     * @param channelId      对应频道id
     * @param offlineEnabled 通知事件是否存离线
     * @param customInfo     操作者附加的自定义信息，透传给其他人，可缺省
     * @return InvocationFuture<Void>
     */
    private fun closeChannel(channelInfo: ChannelBaseInfo?) {
        channelInfo?.let {

            NIMClient.getService(SignallingService::class.java)
                .close(it.channelId, true, "关闭频道的自定义字段").setCallback(object :
                    RequestCallback<Void?> {
                    override fun onSuccess(param: Void?) {
                        LogUtil.d("关闭频道成功   channelId =  ${it.channelId}", tag = tag)
                    }

                    override fun onFailed(code: Int) {
                        LogUtil.d("关闭频道失败   code==$code", tag = tag)
                    }

                    override fun onException(exception: Throwable?) {
                        LogUtil.d("关闭频道异常  ， exception ==${exception?.toJson()}", tag = tag)
                    }


                })
        } ?: kotlin.run {
            LogUtil.d("请先创建频道或加入频道")
        }

    }


    /**
     * 邀请别人
     * @param channelInfo 频道信息
     * @param account 被邀请人账号
     * @param invitedRequestId 是用来做为此次邀请动作的唯一标识，需要开发者自己生成，并保证唯一性，不同的邀请不能用同一个id，否则可能导致混乱。
     */
    private fun inviteOther(
        channelInfo: ChannelBaseInfo,
        account: String,
        invitedRequestId: String
    ) {
        val param = InviteParamBuilder(channelInfo.channelId, account, invitedRequestId)
        param.offlineEnabled(true)
        NIMClient.getService(SignallingService::class.java).invite(param)
            .setCallback(object : RequestCallback<Void?> {
                override fun onSuccess(param: Void?) {

                    LogUtil.d("邀请成功   channelId =  ${channelInfo.channelId}", tag = tag)


                }

                override fun onFailed(code: Int) {
                    LogUtil.d("邀请失败   code =  $code", tag = tag)
                    if(code == 10202){
                        //邀请的对方不在线
                        TipsToast.showTips("对方不在线，请稍后再试")

                    }

                }

                override fun onException(exception: Throwable?) {
                    LogUtil.d("邀请异常   exception =  ${exception?.toJson()}", tag = tag)

                }
            })

    }


    /**
     * 取消邀请
     * @param channelInfo 频道信息
     * @param account 被邀请人账号
     * @param invitedRequestId  需要传入邀请时生成的id。
     */
    private fun cancelInvite(
        channelInfo: ChannelBaseInfo?,
        account: String,
        invitedRequestId: String
    ) {


        channelInfo?.let {

            val param = InviteParamBuilder(it.channelId, account, invitedRequestId)
            param.offlineEnabled(true)
            NIMClient.getService(SignallingService::class.java).cancelInvite(param)
                .setCallback(object : RequestCallback<Void?> {
                    override fun onSuccess(param: Void?) {

                        LogUtil.d("取消邀请成功   channelId =  ${it.channelId}", tag = tag)


                    }

                    override fun onFailed(code: Int) {
                        LogUtil.d("取消邀请失败   code =  $code", tag = tag)

                    }

                    override fun onException(exception: Throwable) {
                        LogUtil.d("取消邀请异常   exception =  ${exception.toJson()}", tag = tag)

                    }
                })

        } ?: kotlin.run {

            LogUtil.d("请先创建频道或加入频道", tag = tag)

        }


    }

    /**
     * 接受对方邀请并自动加入频道
     * @param invitedEvent 接收到邀请信令的 数据封装
     * @param inviteParam InviteParamBuilder {@link InviteParamBuilder}
     * @param selfUid  自己在频道中对应的uid，大于零有效，无效时服务器会分配随机唯一的uid， 也可以自己生成，但要保证唯一性
     * @return InvocationFuture<Void>
     */
     fun acceptInvite(invitedEvent: InvitedEvent, selfUid: Long) {
        val inviteParam = InviteParamBuilder(
            invitedEvent.channelBaseInfo.channelId,
            invitedEvent.fromAccountId,
            invitedEvent.requestId
        )
        NIMClient.getService(SignallingService::class.java)
            .acceptInviteAndJoin(inviteParam, selfUid)
            .setCallback(object : RequestCallbackWrapper<ChannelFullInfo>() {

                override fun onResult(code: Int, result: ChannelFullInfo?, throwable: Throwable?) {
                    if (code == 200) {
                        LogUtil.d("接收邀请成功", tag = tag)
                        remoteUserJoinChannelLiveData.value=result

                    } else {
                        LogUtil.d(
                            "接收邀请返回的结果 ， code = $code  throwable==${throwable?.toJson()}",
                            tag = tag
                        )

                    }
                }
            })
    }


    /**
     * 拒绝对方邀请
     * @param paramBuilder InviteParamBuilder {@link InviteParamBuilder}
     * @return InvocationFuture<Void>
     */
     fun rejectInvite(invitedEvent: InvitedEvent) {
        val inviteParam = InviteParamBuilder(
            invitedEvent.channelBaseInfo.channelId,
            invitedEvent.fromAccountId,
            invitedEvent.requestId
        )

        NIMClient.getService(SignallingService::class.java).rejectInvite(inviteParam)
    }


    /**
     * 呼叫对方
     * 直接呼叫 ， 用于用户新开一个频道并邀请对方加入频道。该接口为组合接口，等同于用户先创建频道，然后加入频道并邀请对方
     * @param account 对方账号
     * @param selfUid 自己在频道中对应的uid，大于零有效，无效时服务器会分配随机唯一的uid， 也可以自己生成，但要保证唯一性
     */
    private fun call(account: String, selfUid: Long) {


        var requestId = System.currentTimeMillis().toString()
        var paramBuilder = CallParamBuilder(ChannelType.VIDEO, account, requestId)
        paramBuilder.selfUid(selfUid)

        NIMClient.getService(SignallingService::class.java).call(paramBuilder)
            .setCallback(
                object : RequestCallbackWrapper<ChannelFullInfo>() {
                    override fun onResult(
                        code: Int,
                        channelFullInfo: ChannelFullInfo,
                        throwable: Throwable
                    ) {
                        //参考官方文档中关于api以及错误码的说明
                        if (code == ResponseCode.RES_SUCCESS.toInt()) {

                            LogUtil.d(
                                "邀请成功，等待对方接听  channelFullInfo==${channelFullInfo.toJson()}",
                                tag = tag
                            )
                        } else {

                            LogUtil.d(
                                "邀请返回的结果 ， code = $code  throwable==${throwable?.toJson()}",
                                tag = tag
                            )
                        }

                    }
                })

    }
}




